﻿using Microsoft.Exchange.WebServices.Data;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Web;
using System.Collections.Specialized;
using System.Configuration;
using Microsoft.TeamFoundation.Framework.Client;
using System.IO;

namespace TicketProcessingService
{
    public class ProcessTickets
    {

        public void NotifyDelays()
        {
            //get tpc name from config file and connect. Get Configuration of TFS
            NameValueCollection appSettings = ConfigurationManager.AppSettings;
            TfsTeamProjectCollection tpc = new TfsTeamProjectCollection(new Uri("http://" + appSettings["Tfs"] + ":8080/tfs/" + appSettings["Collection"]));
            TfsConfigurationServer configSvr = new TfsConfigurationServer(new Uri("http://" + Environment.MachineName + ":8080/tfs"));
            ITeamFoundationRegistry regSvc = configSvr.GetService<ITeamFoundationRegistry>();
            //from tfs registry get the email address of from 
            string address = regSvc.GetValue(@"/Service/Integration/Settings/EmailNotificationFromAddress");
            WorkItemStore wiStore = tpc.GetService<WorkItemStore>();
            //load configuration file
            XmlDocument doc = new XmlDocument();
            doc.Load("/TicketM/App_Data/AreaNoDaysEmails.xml");
            //get all the tickets by running the WITD query
            WorkItemCollection wiColl = wiStore.Query("SELECT [System.Id], [System.WorkItemType], [System.Title], [System.AssignedTo], [System.State], [SSGS.MyEfforts] FROM WorkItems WHERE [System.WorkItemType] = 'Ticket'");
            foreach (WorkItem wi in wiColl)
            {
                //for each ticket check date when it was last changed by going through its history
                string project = wi.Project.Name;
                RevisionCollection revColl = wi.Revisions;
                DateTime LastStateChangedDate = DateTime.Now;
                foreach (Revision rev in revColl)
                {
                    if (rev.Fields["System.State"].Value != rev.Fields["System.State"].OriginalValue)
                    {
                        LastStateChangedDate = DateTime.Parse(rev.Fields["Microsoft.VSTS.Common.StateChangeDate"].Value.ToString());
                    }
                }

                //fetch max allowed days for that area from xml file   
                string areaPath;
                if (wi.AreaPath.Contains('\\'))
                {
                    areaPath = wi.AreaPath.Substring(wi.AreaPath.LastIndexOf('\\') + 1, wi.AreaPath.Length - wi.AreaPath.LastIndexOf('\\') - 1);
                }
                else
                {
                    areaPath = wi.AreaPath;
                }
                XmlNode node = doc.DocumentElement.SelectSingleNode("/Area_Email_Days/Area[@Name='" + areaPath + "' and @Project='" + project + "']");
                //if escalation has not been enabled for that area, node is null. Process escalation only if node is not null
                if (node != null)
                {
                    int EscalateAfter = Convert.ToInt32(node.Attributes["Days"].Value.ToString());

                    //check if the actual days exceed the max days and that ticket is not already escalated
                    if ((DateTime.Now - LastStateChangedDate).Days > EscalateAfter && wi.Fields["SSGS.Escalated"].Value.ToString() == "No")
                    {
                        //since we are in, this ticket needs to be escalated - send email
                        //read exchange server version from app file and accordingly create instance
                        ExchangeService exchService = null;
                        string exchVer = appSettings["ExVer"];

                        switch (exchVer)
                        {
                            case "Exchange 2007 SP1":
                                exchService = new ExchangeService(ExchangeVersion.Exchange2007_SP1);
                                break;
                            case "Exchange 2010":
                                exchService = new ExchangeService(ExchangeVersion.Exchange2010);
                                break;
                            case "Exchange 2010 SP1":
                                exchService = new ExchangeService(ExchangeVersion.Exchange2010_SP1);
                                break;
                            case "Exchange 2010 SP2":
                                exchService = new ExchangeService(ExchangeVersion.Exchange2010_SP2);
                                break;
                            case "Exchange 2013":
                                exchService = new ExchangeService(ExchangeVersion.Exchange2013);
                                break;
                            default:
                                break;
                        }

                        string UName = appSettings["UserName"];
                        string pwd = appSettings["Password"];
                        string Domain = appSettings["Domain"];
                        WebCredentials credentials = new WebCredentials(UName, pwd, Domain);

                        exchService.Credentials = credentials;
                        string ExhName = appSettings["ExchServerName"];
                        //use the exchange server webservice to send email
                        exchService.Url = new Uri("https://" + ExhName + "/EWS/Exchange.asmx");
                        try
                        {
                            //load message with its properties
                            EmailMessage message = new EmailMessage(exchService);
                            message.Body = "Ticket number " + wi.Id + " having title " + wi.Title + " is in the same state for the last " + (DateTime.Now - LastStateChangedDate).Days.ToString() + " Days.";

                            message.ToRecipients.Add(node.Attributes["Email"].Value);
                            message.From = address;
                            message.Subject = "Escalation for unmoved ticket";

                            message.Send();
                            //after sending the email, let us now set the values of fields of ticket and save the ticket
                            string escalationEmail = node.Attributes["Email"].Value.ToString();
                            string escalationUserName = escalationEmail.Substring(0, escalationEmail.IndexOf('@'));
                            wi.Fields["System.AssignedTo"].Value =
                            wi.Fields["SSGS.Escalated"].Value = "Yes";
                            wi.Save();
                        }
                        catch (Exception ex)
                        {
                            Logger.CreateLogEntry(System.DateTime.Now.ToShortDateString() + "Exception while processing tickets:" + ex.Message);
                        }
                    }

                }
            }
        }
        private string ReadSetting(string key)
        {
            XmlDocument doc = new XmlDocument();
            string path = System.IO.Path.GetFullPath(System.Reflection.Assembly.GetExecutingAssembly().Location);
            path += @"\AreaNoDaysEmails.xml";
            Console.WriteLine(path);

            return doc.SelectSingleNode("/configuration/appSettings/add[@key='" + key + "']").Attributes["value"].Value;
        }

        private bool CertificateValidationCallBack(
                           object sender,
                           System.Security.Cryptography.X509Certificates.X509Certificate certificate,
                           System.Security.Cryptography.X509Certificates.X509Chain chain,
                           System.Net.Security.SslPolicyErrors sslPolicyErrors)
        {
            // If the certificate is a valid, signed certificate, return true.ng
            if (sslPolicyErrors == System.Net.Security.SslPolicyErrors.None)
            {
                return true;
            }
            // If there are errors in the certificate chain, look at each error to determine the cause.
            if ((sslPolicyErrors & System.Net.Security.SslPolicyErrors.RemoteCertificateChainErrors) != 0)
            {
                if (chain != null && chain.ChainStatus != null)
                {
                    foreach (System.Security.Cryptography.X509Certificates.X509ChainStatus status in chain.ChainStatus)
                    {
                        if ((certificate.Subject == certificate.Issuer) &&
                                           (status.Status == System.Security.Cryptography.X509Certificates.X509ChainStatusFlags.UntrustedRoot))
                        {
                            // Self-signed certificates with an untrusted root are valid. 
                            continue;
                        }
                        else
                        {
                            if (status.Status != System.Security.Cryptography.X509Certificates.X509ChainStatusFlags.NoError)
                            {
                                // If there are any other errors in the certificate chain, the certificate is invalid,
                                // so the method returns false.
                                return false;
                            }
                        }
                    }
                }
                // When processing reaches this line, the only errors in the certificate chain are 
                // untrusted root errors for self-signed certificates. These certificates are valid
                // for default Exchange server installations, so return true.
                return true;
            }
            else
            {
                // In all other cases, return false.
                return false;
            }
        }
    }
    public class Logger
    {
        public static void CreateLogEntry(string Message)
        {
            String LogPath = Path.GetPathRoot(System.Environment.SystemDirectory) + @"\Program Files\SSGS\Logs";
            if (!Directory.Exists(LogPath))
                Directory.CreateDirectory(LogPath);
            string FileName = DateTime.Now.Month.ToString() + DateTime.Now.Year.ToString() + ".log";
            if (!File.Exists(LogPath + "\\" + FileName))
                File.CreateText(FileName);
            StreamWriter log = File.AppendText(LogPath + "\\" + FileName);
            log.WriteLine(Message);
            log.Flush();
            log.Close();
        }
    }
}